package com.example.examsystem.service;

import com.example.examsystem.dto.CategoryDto;
import com.example.examsystem.dto.PageResponse;
import com.example.examsystem.exception.BusinessException;
import com.example.examsystem.model.Category;
import com.example.examsystem.model.Subject;
import com.example.examsystem.repository.CategoryRepository;
import com.example.examsystem.repository.SubjectRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 学科分类服务
 * 处理分类相关的业务逻辑
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class CategoryService {
    
    private final CategoryRepository categoryRepository;
    private final SubjectRepository subjectRepository;
    
    /**
     * 分页查询分类列表
     */
    public PageResponse<CategoryDto> getCategories(int page, int size, String name, 
                                                  String code, Long subjectId, String status) {
        log.debug("查询分类列表 - 页码: {}, 大小: {}, 筛选条件: 名称={}, 代码={}, 学科ID={}, 状态={}", 
                page, size, name, code, subjectId, status);
        
        Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
        Page<Category> categoryPage = categoryRepository.findByQuery(name, code, subjectId, status, pageable);
        
        List<CategoryDto> content = categoryPage.getContent().stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());
        
        return new PageResponse<>(
            content,
            categoryPage.getNumber(),
            categoryPage.getSize(),
            categoryPage.getTotalElements(),
            categoryPage.getTotalPages()
        );
    }
    
    /**
     * 获取分类详情
     */
    public CategoryDto getCategory(Long id) {
        log.debug("获取分类详情 - ID: {}", id);
        Category category = categoryRepository.findById(id)
            .orElseThrow(() -> new BusinessException("分类不存在"));
        return convertToDto(category);
    }
    
    /**
     * 创建分类
     */
    @Transactional
    public CategoryDto createCategory(CategoryDto categoryDto) {
        log.debug("创建分类 - 名称: {}, 代码: {}", categoryDto.getName(), categoryDto.getCode());
        
        // 检查学科是否存在
        if (!subjectRepository.existsById(categoryDto.getSubjectId())) {
            throw new BusinessException("学科不存在");
        }
        
        // 检查分类代码是否已存在
        if (categoryRepository.existsByCode(categoryDto.getCode())) {
            throw new BusinessException("分类代码已存在");
        }
        
        Category category = new Category();
        category.setName(categoryDto.getName());
        category.setCode(categoryDto.getCode());
        category.setDescription(categoryDto.getDescription());
        category.setSubjectId(categoryDto.getSubjectId());
        category.setStatus(categoryDto.getStatus() != null ? categoryDto.getStatus() : "ACTIVE");
        category.setCreatedBy(1L); // TODO: 从当前用户获取
        category.setCreatedAt(LocalDateTime.now());
        category.setUpdatedAt(LocalDateTime.now());
        
        Category savedCategory = categoryRepository.save(category);
        log.info("分类创建成功 - ID: {}, 名称: {}", savedCategory.getId(), savedCategory.getName());
        
        return convertToDto(savedCategory);
    }
    
    /**
     * 更新分类
     */
    @Transactional
    public CategoryDto updateCategory(Long id, CategoryDto categoryDto) {
        log.debug("更新分类 - ID: {}, 名称: {}", id, categoryDto.getName());
        
        Category category = categoryRepository.findById(id)
            .orElseThrow(() -> new BusinessException("分类不存在"));
        
        // 检查学科是否存在
        if (!subjectRepository.existsById(categoryDto.getSubjectId())) {
            throw new BusinessException("学科不存在");
        }
        
        // 检查分类代码是否已被其他分类使用
        if (!category.getCode().equals(categoryDto.getCode()) && 
            categoryRepository.existsByCodeAndIdNot(categoryDto.getCode(), id)) {
            throw new BusinessException("分类代码已存在");
        }
        
        category.setName(categoryDto.getName());
        category.setCode(categoryDto.getCode());
        category.setDescription(categoryDto.getDescription());
        category.setSubjectId(categoryDto.getSubjectId());
        category.setStatus(categoryDto.getStatus());
        category.setUpdatedAt(LocalDateTime.now());
        
        Category updatedCategory = categoryRepository.save(category);
        log.info("分类更新成功 - ID: {}, 名称: {}", updatedCategory.getId(), updatedCategory.getName());
        
        return convertToDto(updatedCategory);
    }
    
    /**
     * 删除分类
     */
    @Transactional
    public void deleteCategory(Long id) {
        log.debug("删除分类 - ID: {}", id);
        
        Category category = categoryRepository.findById(id)
            .orElseThrow(() -> new BusinessException("分类不存在"));
        
        // TODO: 检查是否有关联的试题
        
        categoryRepository.delete(category);
        log.info("分类删除成功 - ID: {}, 名称: {}", id, category.getName());
    }
    
    /**
     * 根据学科ID获取分类列表
     */
    public List<CategoryDto> getCategoriesBySubject(Long subjectId) {
        log.debug("根据学科ID获取分类列表 - 学科ID: {}", subjectId);
        List<Category> categories = categoryRepository.findBySubjectIdAndStatusOrderByName(subjectId, "ACTIVE");
        return categories.stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());
    }

    /**
     * 获取所有激活的分类
     */
    public List<CategoryDto> getAllActiveCategories() {
        log.debug("获取所有激活的分类");
        List<Category> categories = categoryRepository.findByStatusOrderByName("ACTIVE");
        return categories.stream()
            .map(this::convertToDto)
            .collect(Collectors.toList());
    }

    /**
     * 根据ID获取分类
     */
    public CategoryDto getCategoryById(Long id) {
        log.debug("根据ID获取分类 - ID: {}", id);
        Category category = categoryRepository.findById(id)
            .orElseThrow(() -> new BusinessException("分类不存在"));
        return convertToDto(category);
    }
    
    /**
     * 转换为DTO
     */
    private CategoryDto convertToDto(Category category) {
        CategoryDto dto = new CategoryDto();
        dto.setId(category.getId());
        dto.setName(category.getName());
        dto.setCode(category.getCode());
        dto.setDescription(category.getDescription());
        dto.setSubjectId(category.getSubjectId());
        dto.setStatus(category.getStatus());
        dto.setCreatedBy(category.getCreatedBy());
        dto.setCreatedAt(category.getCreatedAt());
        dto.setUpdatedAt(category.getUpdatedAt());
        
        // 设置学科名称
        if (category.getSubject() != null) {
            dto.setSubjectName(category.getSubject().getName());
        }
        
        return dto;
    }
}

